﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using Ignitron.EEngine.Adapters.DX.System;
using SharpDX;

namespace Ignitron.EEngine.Adapters.DX.Graphics
{
    /// <summary>
    /// Class representing a camera
    /// </summary>
    internal class Camera
    {
        private float PositionX;
        private float PositionY;
        private float PositionZ;

        private float RotationX;
        private float RotationY;
        private float RotationZ;

        private float mFOV = (float)(Math.PI / 4);
        private float mNear = 0f, mFar= 1000f;

        public Matrix ViewMatrix
        { get; private set; }

        public Matrix ProjectionMatrix
        { get; private set; }

        public Camera()
        {
            AlphaOpacity = 1f; 
        }

        public float AlphaOpacity
        { get; set; }

        public void SetPosition(float x, float y, float z)
        {
            PositionX = x;
            PositionY = y;
            PositionZ = z;

            Compute();
        }

        public void SetRotation(float x, float y, float z)
        {
            RotationX = x;
            RotationY = y;
            RotationZ = z;

            Compute();
        }

        public Vector3 GetPosition()
        {
            return new Vector3(PositionX, PositionY, PositionZ);
        }

        public Vector3 GetRotation()
        {
            return new Vector3(RotationX, RotationY, RotationZ);
        }

        public void SetLookAt(Vector3 position, Vector3 lookAt, Vector3 up)
        {
            ViewMatrix = Matrix.LookAtRH(position, lookAt, up);
        }

        public void SetFOV(float fov)
        {
            mFOV = fov;
        }

        public void SetNearFarLimits(float near, float far)
        {
            mNear = near;
            mFar = far;
        }

        private void Compute()
        {
            // Setup the position of the camera in the world.
            var position = new Vector3(PositionX, PositionY, PositionZ);

            // Setup where the camera is looking by default.
            var lookAt = new Vector3(0, 0, 1);

            // Set the yaw (Y axis), pitch (X axis), and roll (Z axis) rotations in radians.
            var pitch = RotationX * 0.0174532925f;
            var yaw = RotationY * 0.0174532925f;
            var roll = RotationZ * 0.0174532925f;

            // Create the rotation matrix from the yaw, pitch, and roll values.
            var rotationMatrix = Matrix.RotationYawPitchRoll(yaw, pitch, roll);

            // Transform the lookAt and up vector by the rotation matrix so the view is correctly rotated at the origin.
            lookAt = Vector3.TransformCoordinate(lookAt, rotationMatrix);
            var up = Vector3.TransformCoordinate(Vector3.UnitY, rotationMatrix);

            // Translate the rotated camera position to the location of the viewer.
            lookAt = position + lookAt;

            // Finally create the view matrix from the three updated vectors.
            ViewMatrix = Matrix.LookAtRH(position, lookAt, up);
        }

        /// <summary>
        /// Updates the perspective matrix - TO-DO:
        /// </summary>
        public void UpdatePerspective(int windowWidth, int windowHeight)
        {
            ProjectionMatrix = Matrix.PerspectiveFovRH(mFOV, (float)(windowWidth) / (float)windowHeight, mNear, mFar);
        }
    }
}
